//
//  JQAlertView.m
//  AlertViewDemo
//
//  Created by James on 15/7/22.
//  Copyright (c) 2015年 JQ. All rights reserved.
//

#import "JQAlertView.h"

#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height

static CGFloat const kJQAlertViewButtonHeightPadding = 40.f;
static CGSize const kJQAlertViewDefaultSize = {280,180};

#pragma mark - Extensions

@class JQAlertOverLay,JQAlertViewQueue;
@interface JQAlertView ()

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *message;
@property (nonatomic, strong) NSString *okButtonTitle;
@property (nonatomic, strong) NSString *cancelButtonTitle;

@property (nonatomic ,copy) JQAlertButtonClickBlock buttonBlock;

@property (nonatomic, strong) UIView *contentView;

@property (nonatomic, strong) UIColor *alertBackgroundColor;

@property (nonatomic, strong) UIFont *titleFont;
@property (nonatomic, strong) UIFont *messageFont;
@property (nonatomic, strong) UIFont *buttonTitleFont;

@property (nonatomic, strong) UIColor *titleColor;
@property (nonatomic, strong) UIColor *messageColor;
@property (nonatomic, strong) UIColor *buttonColor;

@property (nonatomic, assign) CGFloat titleLabelHeight;
@property (nonatomic, assign) CGFloat messageLabelHeight;

@property UIInterfaceOrientation currentOrientation;
@property JQAlertAnimation currentAnimation;

- (void)showFromAlertQueue;

@end

#pragma mark - Helper classes

@interface JQAlertOverLay : UIView

@end

@class JQAlertView;
@interface JQAlertViewQueue : NSObject

@property (nonatomic, strong) NSMutableArray *alerts;
@property (nonatomic, strong) UIWindow *sharedWindow;
@property (nonatomic, strong) JQAlertOverLay *sharedOverLay;

+ (JQAlertViewQueue *)sharedQueue;

- (void)addAlert:(JQAlertView *)alert;
- (void)removeAlert:(JQAlertView *)alert;

@end

#pragma mark - Alert Implement

@implementation JQAlertView

#pragma mark - Class Methods

+ (instancetype)alertWithTitle:(NSString *)title
                       message:(NSString *)msg
                    clickBlock:(JQAlertButtonClickBlock)clickBlock
{
    return [[JQAlertView alloc] initWithTitle:title message:msg clickBlock:clickBlock];
}

+ (instancetype)alertWithTitle:(NSString *)title
                       message:(NSString *)msg
                      okButton:(NSString *)okBtnTitle
                  cancelButton:(NSString *)cancelBtnTitle
                    clickBlock:(JQAlertButtonClickBlock)clickBlock
{
    return [[JQAlertView alloc] initWithTitle:title message:msg okButton:okBtnTitle cancelButton:cancelBtnTitle clickBlock:clickBlock];
}

#pragma mark - Instance Methods

- (instancetype)initWithTitle:(NSString *)title
                      message:(NSString *)msg
                   clickBlock:(JQAlertButtonClickBlock)clickBlock
{
    return [self initWithTitle:title message:msg okButton:@"确定" cancelButton:@"取消" clickBlock:clickBlock];
}

- (instancetype)initWithTitle:(NSString *)title
                      message:(NSString *)msg
                     okButton:(NSString *)okBtnTitle
                 cancelButton:(NSString *)cancelBtnTitle
                   clickBlock:(JQAlertButtonClickBlock)clickBlock
{
    if (self = [super initWithFrame:CGRectMake(0, 0, kJQAlertViewDefaultSize.width, kJQAlertViewDefaultSize.height)]) {
        self.title = title;
        self.message = msg;
        self.okButtonTitle = okBtnTitle;
        self.cancelButtonTitle = cancelBtnTitle;
        self.buttonBlock = clickBlock;
        
        [self initAttributes];
        [self configFrame];
        [self configAlertView];
        
        self.currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
        
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willChangeRotationNoti:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
    }
    return self;
}

- (void)initAttributes{
    self.alertBackgroundColor = [UIColor whiteColor];
    
    self.titleFont = [UIFont boldSystemFontOfSize:15];
    self.messageFont = [UIFont systemFontOfSize:13];
    self.buttonTitleFont = [UIFont systemFontOfSize:15];
    
    self.titleColor = [UIColor blackColor];
    self.messageColor = [UIColor blackColor];
    self.buttonColor = [UIColor blackColor];
}

#pragma mark - Draw alert view


- (void)configFrame{
    
    self.layer.transform = CATransform3DIdentity;
    self.transform = CGAffineTransformIdentity;
    
    self.frame = [self defaultFrame];
    CGFloat titleHeight = 40;
    if (self.title && self.title.length > 0) {
        CGRect titleBounds = [self.title boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX)
                                                      options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                   attributes:@{NSFontAttributeName:self.titleFont}
                                                      context:nil];
        titleHeight = ceilf(MAX(titleBounds.size.height, titleHeight));
        self.titleLabelHeight = titleHeight;
    }
    
    CGFloat messageHeight = 40;
    if (self.message && self.message.length > 0) {
        CGRect messageBounds = [self.message boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.frame), CGFLOAT_MAX)
                                                          options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                       attributes:@{NSFontAttributeName:self.messageFont}
                                                          context:nil];
        messageHeight = ceilf(MAX(messageBounds.size.height, messageHeight));
        self.messageLabelHeight = messageHeight;
    }
    
    self.frame = [self frameWithWidth:kJQAlertViewDefaultSize.width Height:titleHeight + messageHeight + kJQAlertViewButtonHeightPadding];
}


- (void)configAlertView{
    self.backgroundColor = self.alertBackgroundColor;
    self.layer.borderWidth = 1.f;
    self.layer.borderColor = [UIColor lightGrayColor].CGColor;
    self.layer.masksToBounds = YES;
    self.layer.cornerRadius = 5.f;
    self.layer.shadowColor = [UIColor blackColor].CGColor;
    self.layer.shadowOpacity = 0.8;
    self.layer.shadowOffset = CGSizeMake(5, 5);
    self.layer.shadowRadius = 5.f;
    
    UIView *view = [[UIView alloc] initWithFrame:self.bounds];
    [self addSubview:view];
    self.contentView = view;
    
    CGFloat buttonXPadding = 0;
    CGFloat buttonWidth = CGRectGetWidth(self.frame);
    NSInteger buttonBaseTag = 101;
    
    if ((self.okButtonTitle && self.okButtonTitle.length > 0) && (self.cancelButtonTitle && self.cancelButtonTitle.length > 0)) {
        buttonWidth = buttonWidth/2;
    }
    if (self.okButtonTitle && self.okButtonTitle.length > 0) {
        UIButton *ok = [[UIButton alloc] initWithFrame:CGRectMake(buttonXPadding, CGRectGetHeight(self.frame)-kJQAlertViewButtonHeightPadding, buttonWidth, kJQAlertViewButtonHeightPadding)];
        ok.tag = buttonBaseTag++;
        ok.backgroundColor = [UIColor redColor];
        
        [ok setTitle:self.okButtonTitle forState:UIControlStateNormal];
        [ok addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.contentView addSubview:ok];
        buttonXPadding = buttonXPadding + buttonWidth;
        
    }
    
    if (self.cancelButtonTitle && self.cancelButtonTitle.length > 0) {
        UIButton *cancel = [[UIButton alloc] initWithFrame:CGRectMake(buttonXPadding, CGRectGetHeight(self.frame)-kJQAlertViewButtonHeightPadding, buttonWidth, kJQAlertViewButtonHeightPadding)];
        cancel.tag = buttonBaseTag++;
        cancel.backgroundColor = [UIColor greenColor];
        
        [cancel setTitle:self.cancelButtonTitle forState:UIControlStateNormal];
        [cancel addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.contentView addSubview:cancel];
        buttonXPadding = buttonXPadding + buttonWidth;
    }
    
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), self.titleLabelHeight)];
    title.text = self.title;
    title.textColor = self.titleColor;
    title.font = self.titleFont;
    title.textAlignment = NSTextAlignmentCenter;
    
    UILabel *msg = [[UILabel alloc] initWithFrame:CGRectMake(0, self.titleLabelHeight, CGRectGetWidth(self.frame), self.messageLabelHeight)];
    msg.text = self.message;
    msg.textColor = self.messageColor;
    msg.font = self.messageFont;
    msg.textAlignment = NSTextAlignmentCenter;
    
    [self.contentView addSubview:title];
    [self.contentView addSubview:msg];
}

- (CGRect)defaultFrame{
    return [self frameWithWidth:kJQAlertViewDefaultSize.width Height:kJQAlertViewDefaultSize.height];
}

- (CGRect)frameWithWidth:(CGFloat)width Height:(CGFloat)height{
    CGRect windowFrame = [JQAlertViewQueue sharedQueue].sharedWindow.bounds;
    return CGRectIntegral(CGRectInset(windowFrame, (windowFrame.size.width - width)/2, (windowFrame.size.height - height)/2));
}

#pragma mark - Show & dismiss

- (void)show{
    [self showWithAnimation:JQAlertAnimationDefault];
}

- (void)showWithAnimation:(JQAlertAnimation)animation{
    self.currentAnimation = animation;
    [[JQAlertViewQueue sharedQueue] addAlert:self];
}

- (void)showFromAlertQueue{
    [[[JQAlertViewQueue sharedQueue] sharedWindow] addSubview:[JQAlertViewQueue sharedQueue].sharedOverLay];
    [[[JQAlertViewQueue sharedQueue] sharedOverLay] addSubview:self];
    [[[JQAlertViewQueue sharedQueue] sharedWindow] makeKeyAndVisible];

    self.alpha = 0.1;
    CGAffineTransform orignalAffineTran = self.transform;
    CATransform3D orignal3DTran = self.layer.transform;
    if (self.currentAnimation == JQAlertAnimationDefault)
    {
        self.transform = CGAffineTransformScale(orignalAffineTran, 0.8, 0.8);
        [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.transform = orignalAffineTran;
            self.alpha = 1.f;
        } completion:^(BOOL finish){
            
        }];
        
    }
    else if (self.currentAnimation == JQAlertAnimationDropDown){
        CGAffineTransform tran1 = CGAffineTransformTranslate(orignalAffineTran, 0, -SCREEN_HEIGHT/2);
        self.transform = CGAffineTransformRotate(tran1, M_PI_4/2);
        [UIView animateWithDuration:1.f delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.transform = orignalAffineTran;
            self.alpha = 1.f;
        } completion:^(BOOL finish){
            
        }];
    }
    else if (self.currentAnimation == JQAlertAnimationFlyOut){
        CGAffineTransform tran1 = CGAffineTransformTranslate(orignalAffineTran, 0, -SCREEN_HEIGHT/2);
        CGAffineTransform tran2 = CGAffineTransformScale(tran1, 0.3, 0.3);
        self.transform = tran2;

        [UIView animateKeyframesWithDuration:0.5f delay:0 options:UIViewKeyframeAnimationOptionCalculationModePaced animations:^{
            [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:0.8 animations:^{
                self.transform = CGAffineTransformTranslate(tran2, 0, SCREEN_HEIGHT/2);
                self.alpha = 0.5f;
            }];
            [UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:0.2 animations:^{
                self.transform = orignalAffineTran;
                self.alpha = 1.f;
            }];
        } completion:nil];
        
    }
    else if (self.currentAnimation == JQAlertAnimationFlipHorizontal){
        
        CATransform3D tran = CATransform3DIdentity;
        tran.m34 = 1.0/500;
        tran = CATransform3DRotate(tran, M_PI_2, 0, 1, 0);
        self.layer.transform = tran;
        
        
        [UIView animateWithDuration:1.2 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.layer.transform = orignal3DTran;
            self.alpha = 1.f;
        } completion:^(BOOL finish){
        }];
    }
}

- (void)dismiss{
    [self dismissWithAnimation:JQAlertAnimationDefault];
}

- (void)dismissWithAnimation:(JQAlertAnimation)animation{

    //只有全局Alert队列中的最后一个Alert，才需要消失动画，并移除所有背景
    if ([JQAlertViewQueue sharedQueue].alerts.count > 1) {
        [[JQAlertViewQueue sharedQueue] removeAlert:self];
        self.alpha = 0;
        return;
    }
    
    CGAffineTransform orignalAffineTran = self.transform;
    CATransform3D orignal3DTran = self.layer.transform;
    if (animation == JQAlertAnimationDefault)
    {
        CGAffineTransform trans = CGAffineTransformScale(orignalAffineTran, 0.8, 0.8);
        [UIView animateWithDuration:0.2 animations:^{
            self.transform = trans;
            self.alpha = 0;
        }completion:^(BOOL finish){
            [self cleanup];
        }];
        
    }
    else if (animation == JQAlertAnimationDropDown){
        CGAffineTransform tran = CGAffineTransformTranslate(orignalAffineTran, 0, SCREEN_HEIGHT/2);
        CGAffineTransform tran1 = CGAffineTransformRotate(tran, M_PI_4/2);
        
        [UIView animateWithDuration:0.4f delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
            self.transform = tran1;
            self.alpha = 0;
        } completion:^(BOOL finish){
            [self cleanup];
        }];
    }
    else if (animation == JQAlertAnimationFlyOut){
        
    }
    else if (animation == JQAlertAnimationFlipHorizontal){
        CATransform3D tran = CATransform3DInvert(orignal3DTran);
        tran.m34 = 1.0/500;
        tran = CATransform3DRotate(tran, M_PI_2, 0, 1, 0);

        [UIView animateWithDuration:5 animations:^{
            self.layer.transform = tran;
            self.alpha = 0.1f;
        } completion:^(BOOL finish){
            [self cleanup];
        }];
    }
}

- (void)cleanup{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[JQAlertViewQueue sharedQueue].sharedWindow resignKeyWindow];
    [JQAlertViewQueue sharedQueue].sharedWindow = nil;
    [JQAlertViewQueue sharedQueue].sharedOverLay = nil;
    [[JQAlertViewQueue sharedQueue].alerts removeAllObjects];
//    [[[[UIApplication sharedApplication] delegate] window] makeKeyAndVisible];
}

#pragma mark - Rotation

- (void)willChangeRotationNoti:(NSNotification *)noti{
    UIInterfaceOrientation orientation = [[[noti userInfo] objectForKey:UIApplicationStatusBarOrientationUserInfoKey] integerValue];
    if (orientation != self.currentOrientation) {
        [self rotateToOrientation:orientation];
    }
}

- (CGAffineTransform)transformForOrientation:(UIInterfaceOrientation)orientation{
    
    CGAffineTransform transform = [JQAlertViewQueue sharedQueue].sharedWindow.transform;
    if (self.currentOrientation == UIInterfaceOrientationLandscapeLeft){
        if (orientation == UIInterfaceOrientationPortrait){
            transform = CGAffineTransformMakeRotation(M_PI_2);
        }
        else if(orientation == UIInterfaceOrientationPortraitUpsideDown){
            transform = CGAffineTransformMakeRotation(-M_PI_2);
        }
        else if (orientation == UIInterfaceOrientationLandscapeRight){
            transform = CGAffineTransformMakeRotation(M_PI);
        }
    }else if (self.currentOrientation == UIInterfaceOrientationLandscapeRight){
        if (orientation == UIInterfaceOrientationPortrait){
            transform = CGAffineTransformMakeRotation(-M_PI_2);
        }
        else if(orientation == UIInterfaceOrientationPortraitUpsideDown){
            transform = CGAffineTransformMakeRotation(M_PI_2);
        }
        else if (orientation == UIInterfaceOrientationLandscapeLeft){
            transform = CGAffineTransformMakeRotation(M_PI);
        }
    }else if (self.currentOrientation == UIInterfaceOrientationPortrait){
        if (orientation == UIInterfaceOrientationPortraitUpsideDown){
            transform = CGAffineTransformMakeRotation(M_PI);
        }else if(orientation == UIInterfaceOrientationLandscapeLeft){
            transform = CGAffineTransformMakeRotation(-M_PI_2);
        }else if (orientation == UIInterfaceOrientationLandscapeRight){
            transform = CGAffineTransformMakeRotation(M_PI_2);
        }
    }else if (self.currentOrientation == UIInterfaceOrientationPortraitUpsideDown){
        if (orientation == UIInterfaceOrientationPortrait){
            transform = CGAffineTransformMakeRotation(M_PI);
        }else if(orientation == UIInterfaceOrientationLandscapeLeft){
            transform = CGAffineTransformMakeRotation(M_PI_2);
        }else if (orientation == UIInterfaceOrientationLandscapeRight){
            transform = CGAffineTransformMakeRotation(-M_PI_2);
        }
    }
    
    return CGAffineTransformConcat(self.transform, transform);
}

- (void)rotateToOrientation:(UIInterfaceOrientation)orientation{
    CGAffineTransform targetTransform = [self transformForOrientation:orientation];
    
    // block used for repositioning ourselves to account for keyboard and interface orientation changes

    CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
    [UIView animateWithDuration:duration animations:^{
        self.transform = targetTransform;
//        self.layer.transform = CATransform3DMakeAffineTransform(targetTransform);
    } completion:^(BOOL finish){
//        self.transform = CGAffineTransformIdentity;
//        self.layer.transform = CATransform3DIdentity;
        self.currentOrientation = orientation;
    }];

}

#pragma mark - Button action

- (void)buttonClick:(UIButton *)sender{
    
    if (self.buttonBlock) {
        self.buttonBlock(self,sender.tag - 101);
    }
    [self dismissWithAnimation:self.currentAnimation];
}

@end

#pragma mark - Helper Classes Implement

@implementation JQAlertOverLay

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.opaque = NO;
        //        self.alpha = 0.0;
    }
    return self;
}

- (void)drawRect:(CGRect)rect{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    UIColor *gradientOuter = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.4];
    UIColor *gradientInner = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0.1];
    
    NSArray *radialGradientColors = @[(id)gradientInner.CGColor, (id)gradientOuter.CGColor];
    CGFloat radialGradientLocations[] = {0, 0.5, 1};
    CGGradientRef radialGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)radialGradientColors, radialGradientLocations);
    
    // main shape
    UIBezierPath *rectanglePath = [UIBezierPath bezierPathWithRect: CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)];
    CGContextSaveGState(context);
    [rectanglePath addClip];
    CGContextDrawRadialGradient(context, radialGradient,
                                CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height / 2), rect.size.width / 4,
                                CGPointMake(rect.origin.x + rect.size.width / 2, rect.origin.y + rect.size.height / 2), rect.size.width,
                                kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
    CGContextRestoreGState(context);
    
    CGGradientRelease(radialGradient);
    CGColorSpaceRelease(colorSpace);
}

@end

@implementation JQAlertViewQueue

+ (JQAlertViewQueue *)sharedQueue{
    static JQAlertViewQueue *sharedQueue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedQueue = [[self alloc] init];
    });
    return sharedQueue;
}

- (UIWindow *)sharedWindow{
    if (_sharedWindow == nil) {
        _sharedWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        _sharedWindow.opaque = NO;
        _sharedWindow.windowLevel = UIWindowLevelAlert + 2;
        
//        BOOL isIpad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (UIInterfaceOrientationIsLandscape(orientation)) {
            CGAffineTransform transform = _sharedWindow.transform;
            transform = CGAffineTransformRotate(transform, M_PI_2);
            _sharedWindow.transform = transform;
            _sharedWindow.frame = CGRectMake(0, 0, _sharedWindow.frame.size.width, _sharedWindow.frame.size.height);
        }
    }
    return _sharedWindow;
}

- (JQAlertOverLay *)sharedOverLay{
    if (_sharedOverLay == nil) {
        _sharedOverLay = [[JQAlertOverLay alloc] initWithFrame:self.sharedWindow.bounds];
    }
    return _sharedOverLay;
}

- (instancetype)init{
    if (self = [super init]) {
        self.alerts = [[NSMutableArray alloc] init];
        [self sharedWindow];
        [self sharedOverLay];
    }
    return self;
}

- (void)addAlert:(JQAlertView *)alert{
    [self.alerts addObject:alert];
    [alert showFromAlertQueue];
    for (JQAlertView *al in self.alerts) {
        if (al != alert) {
            [al removeFromSuperview];
        }
    }
}

- (void)removeAlert:(JQAlertView *)alert{
    [self.alerts removeObject:alert];
    [[NSNotificationCenter defaultCenter] removeObserver:alert];
    JQAlertView *al = [self.alerts lastObject];
    if (al != nil) {
        [al show];
    }else{
        [alert dismissWithAnimation:alert.currentAnimation];
    }
}

@end



